package com.relife.core.qbc;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.Transient;

import com.relife.common.model.Page;
import com.relife.common.utils.StringUtil;
import com.relife.core.utils.DBUtil;
import org.hibernate.collection.internal.PersistentBag;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.springframework.beans.BeanUtils;



public class QbcQuery implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final String DATA_BEGIN = "_begin";
	private static final String DATA_END = "_end";
	private Object entity = null;
	private Map<String, QbcAlias> alias = new HashMap<String, QbcAlias>();
	private List<Criterion> criterionList = new ArrayList<Criterion>();
	private List<Order> orderList = new ArrayList<Order>();
	private Map<String, String[]> reqMap = null;
	private Class<?> cl = null;

	public <T> QbcQuery(T entity) {
		this.entity = entity;
	}

	public <T> QbcQuery(T entity, Map<String, String[]> map) {
		this.entity = entity;
		this.reqMap = new HashMap<String, String[]>(map);
	}

	public <T> QbcQuery(Class<T> cl) {
		this.cl = cl;
	}

	public void add(Criterion criterion) {
		criterionList.add(criterion);
	}

	public List<QbcAlias> getAlias() {
		List<QbcAlias> ret = new ArrayList<QbcAlias>();
		Iterator<String> it = alias.keySet().iterator();
		while (it.hasNext()) {
			String key = it.next();
			ret.add(alias.get(key));
		}
		return ret;
	}

	public void createAlias(String alias) {
		this.alias.put("alias", new QbcAlias(alias));

	}

	public void createAlias(String alia, JoinType joinType) {
		this.alias.put(alia, new QbcAlias(alia, joinType));
	}

	public void createAlias(String alia, JoinType joinType, Criterion crit) {
		this.alias.put(alia, new QbcAlias(alia, joinType, crit));
	}

	public DetachedCriteria getDetachedCriteria() {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(cl == null ? entity.getClass() : cl);
		// 查询条件

		List<Criterion> critList = getCriterionList();
		if (critList.size() > 0) {
			for (int i = 0; i < critList.size(); i++) {
				detachedCriteria.add(critList.get(i));
			}
		}
		// 排序
		if (orderList.size() > 0) {
			for (int i = 0; i < orderList.size(); i++) {
				detachedCriteria.addOrder(orderList.get(i));
			}
		}
		// 关联
		List<QbcAlias> list = this.getAlias();
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				detachedCriteria.createAlias(list.get(i).getName(), list.get(i).getName(), list.get(i).getJoinType(), list.get(i).getCrit());
			}
		}
		return detachedCriteria;
	}

	public void addOrder(Order order) {
		this.orderList.add(order);
	}

	public List<Criterion> getCriterionList() {
		List<Criterion> list = new ArrayList<Criterion>();
		list.addAll(criterionList);
		if (this.entity != null) {
			Map<String, Object> map = this.getQueryCriterion(null, entity);
			Iterator<String> it = map.keySet().iterator();
			while (it.hasNext()) {
				String key = it.next();
				Object val = map.get(key);
				if (key.indexOf(".") != -1 && !key.endsWith(".id")) {
					QbcAlias a = new QbcAlias(key.substring(0, key.lastIndexOf(".")));
					alias.put(a.getName(), a);
				}
				if (key.contains(DATA_BEGIN)) {
					list.add(Restrictions.ge(key.replace(DATA_BEGIN, ""), val));

				} else if (key.contains(DATA_END)) {
					list.add(Restrictions.le(key.replace(DATA_END, ""), val));

				} else if (val instanceof String) {
					if (key.contains(".id")) {
						list.add(Restrictions.eq(key, val));
					} else {
						list.add(Restrictions.like(key, "%" + val + "%"));
					}

				} else if (val instanceof Date || val instanceof Timestamp) {

				} else if (val instanceof PersistentBag) {

				} else {
					list.add(Restrictions.eq(key, val));
				}
			}
		}
		return list;
	}

	/**
	 * 
	 * @author WU
	 * @date 2015-5-25 下午3:49:27
	 * @param pix
	 * @param entity
	 */
	public <T> Map<String, Object> getQueryCriterion(String pix, T entity) {
		Map<String, Object> map = new HashMap<String, Object>();
		pix = pix == null ? "" : pix + ".";
		try {
			PropertyDescriptor pro[] = BeanUtils.getPropertyDescriptors(entity.getClass());
			for (int i = 0; i < pro.length; i++) {
				String name = pro[i].getName();// 属性名称
				String type = pro[i].getPropertyType().toString();// 属性类型
				boolean isTransient = pro[i].getReadMethod().isAnnotationPresent(Transient.class);
				if (!isTransient) {
					if (reqMap != null && StringUtil.isEmpty(pix) && (reqMap.get(name + DATA_BEGIN) != null || reqMap.get(name + DATA_END) != null)) {
						SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

						if (reqMap.get(name + DATA_BEGIN) != null && StringUtil.isNotEmpty(reqMap.get(name + DATA_BEGIN)[0])) {
							if (type.contains("java.util.Date")) {
								map.put(name + DATA_BEGIN, sd.parseObject(reqMap.get(name + DATA_BEGIN)[0] + " 00:00:00"));
							}
						}
						if (reqMap.get(name + DATA_END) != null && StringUtil.isNotEmpty(reqMap.get(name + DATA_END)[0])) {
							if (type.contains("java.util.Date")) {
								map.put(name + DATA_END, sd.parseObject(reqMap.get(name + DATA_END)[0] + " 23:59:59"));
							}
						}

					} else {
						Object value = pro[i].getReadMethod().invoke(entity, new Object[0]);
						if (StringUtil.isNotEmpty(value) && !name.equals("class")) {
							if (type.contains(".entity.")) {// 属性为entity对象
								map.putAll(getQueryCriterion(pix + name, value));

							} else {
								map.put(pix + name, value);
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

	/**
	 * 
	 * @author WU
	 * @date 2016年4月4日 上午12:33:30
	 * @param sql
	 * @param param
	 * @param map
	 * @param page
	 */
	public static void getWhere(StringBuffer sql, List<Object> param, Map<String, String[]> map, Page page) {
		if (page != null && page.getField() != null) {
			for (int i = 0; i < page.getField().length; i++) {
				if (map.containsKey(page.getField()[i])) {
					String[] value = map.get(page.getField()[i]);
					if (value != null && value.length == 1 && StringUtil.isNotEmpty(value[0])) {
						param.add("%" + value[0] + "%");
						sql.append(" and " + page.getField()[i] + " like ?");
					}

				} else {
					if (map.containsKey(page.getField()[i] + DATA_BEGIN)) {
						String[] value = map.get(page.getField()[i] + DATA_BEGIN);
						if (value != null && value.length == 1 && StringUtil.isNotEmpty(value[0])) {
							param.add(value[0] + " 00:00:00");
							if ("sqlserver".equals(DBUtil.getDBType())) {
								sql.append(" and " + page.getField()[i] + ">=CONVERT(NVARCHAR(100),?,20) ");

							} else if ("oracle".equals(DBUtil.getDBType())) {
								sql.append(" and " + page.getField()[i] + ">=to_date(?,'yyyy-mm-dd hh24:mi:ss') ");

							} else if ("mysql".equals(DBUtil.getDBType())) {

							}
						}

					}
					if (map.containsKey(page.getField()[i] + DATA_END)) {
						String[] value = map.get(page.getField()[i] + DATA_END);
						if (value != null && value.length == 1 && StringUtil.isNotEmpty(value[0])) {
							param.add(value[0] + " 23:59:59");
							if ("sqlserver".equals(DBUtil.getDBType())) {
								sql.append(" and " + page.getField()[i] + "<=CONVERT(NVARCHAR(100),?,20) ");

							} else if ("oracle".equals(DBUtil.getDBType())) {
								sql.append(" and " + page.getField()[i] + "<=to_date(?,'yyyy-mm-dd hh24:mi:ss') ");

							} else if ("mysql".equals(DBUtil.getDBType())) {

							}
						}

					}
				}
			}
		}

		if (StringUtil.isNotEmpty(page.getSort())) {
			//sql.append(" order by " + page.getSort() + " " + StringUtil.toString(page.getOrder()));
		}
	}
}
